/**
 * 增强型的输入框
 * @author Ly
 * @version 1.0a
 */
/**
 * Ly.AdvancedInputBox构造函数
 * @param {Object} config 配置信息
 * config = {
	 width : 200,           // 选择块的宽度
	 height : 400,          // 选择块的高度
	 accepter : element     // 接收器，也是要绑定的INPUT对象
 }
 */
Ly.AdvancedInputBox = function(config /* Object */) {
	var _this = this;
	
	config = config || {};
	
	this.config = {
		width         : config.width || 300,
		height        : config.height || 200,
		acceptor      : config.acceptor || null,
		lock          : false,                       // 锁，用来处理多次触发的情况
		handler       : {
			list      : null,
			shadow    : null
		},
		selectedIndex : -1,
		selectedData  : '',
		dataSources   : []
	};
	this.private = {
		queryData : function(key, evt) {
			var data        = [],
				currentData = '',
				config      = _this.config,
				regExp      = new RegExp(key, 'ig'),
				dataSources = config.dataSources,
				keyCode = (evt || window.event).keyCode;
			
			_this.config.lock = true;
			_this.config.selectedIndex = -1;
			
			for (var i = 0, len = dataSources.length; i < len; ++i) {
				currentData = typeof dataSources[i] === 'object' ? dataSources[i].text : dataSources[i];
				
				key !== '' && currentData.indexOf(key) > -1 &&
					data.push({
						text    : currentData.replace(regExp, '<span class="ly-advancedinputbox-selected-text">' + key + '</span>'),
						dsIndex : i
					});
			}
			
			this.clearLoadedData().updateData(data);
			
			key == '' ? this.hideSelectList() : this.showSelectList();
			
			_this.config.lock = false;
			
			return this;
		},
		clearLoadedData : function() {
			var config = _this.config,
				list   = config.handler.list,
				nodes  = config.handler.list.childNodes;
			
			for (var i = nodes.length - 1; i > -1; --i) {
				list.removeChild(nodes[i]);
			}
			
			return this;
		},
		/**
		 * 更新视图
		 * @param {Array} data 用于更新视图的数据
		 */
		updateData : function(data /* Array */) {
			var node,
				config = _this.config;
			
			for (var i = 0, len = data.length; i < len; ++i) {
				config.handler.list.appendChild(Ly.createElement('div', {
					cls       : 'ly-advancedinputbox-node',
					index     : data[i].dsIndex,
					innerHTML : data[i].text
				}));
			}
			this.bindEvent();
			
			return this;
		},
		// 绑定事件
		bindEvent : function() {
			var config   = _this.config,
				acceptor = config.acceptor,
				nodes    = config.handler.list.childNodes,
				mouseoverEvent = function(obj, event) {
					obj.className = 'ly-advancedinputbox-node-selected';
				},
				mouseoutEvent = function(obj, event) {
					obj.className = 'ly-advancedinputbox-node';
				},
				clickEvent = function(obj, event) {
					config.selectedData = config.dataSources[this.getAttribute('index')];
					
					config.acceptor.value = typeof config.selectedData === 'object' ? config.selectedData.text : config.selectedData;
					
					_this.private.hideSelectList();
				};
			
			for (var i = 0, len = nodes.length; i < len; ++i) {
				Ly.addEvent('onmouseover', mouseoverEvent, nodes[i]);
				Ly.addEvent('onmouseout', mouseoutEvent, nodes[i]);
				Ly.addEvent('onclick', clickEvent, nodes[i]);
			}
			return this;
		},
		// 创建选择框容器
		createElement : function() {
			var config = _this.config;
			
			config.handler.list = Ly.createElement('div', {
				id     : 'ly-advancedinputbox-' + Ly.getCount(),
				cls    : 'ly-advancedinputbox-container',
				style  : [
					'width:'  + config.width + 'px;',
					'height:' + config.height + 'px;',
					'top:'    + (Ly.getY(config.acceptor) + config.acceptor.offsetHeight) + 'px;',
					'left:'   + Ly.getX(config.acceptor) + 'px;'
				].join('')
			});
			
			config.handler.shadow = Ly.createElement('div', {
				id     : 'ly-advancedinputbox-' + Ly.getCount(),
				cls    : 'ly-advancedinputbox-shadow',
				style  : [
					'width:'  + (config.width + 3) + 'px;',
					'height:' + (config.height + 3) + 'px;',
					'top:'    + (Ly.getY(config.acceptor) + config.acceptor.offsetHeight) + 'px;',
					'left:'   + (Ly.getX(config.acceptor) - 1) + 'px;'
				].join(''),
				innerHTML : '<iframe id="ly-advancedinputbox-shadow-iframe" name="ly-advancedinputbox-shadow-iframe"' +
					'frameborder="0" ' +
					'style="width: 100%; height: 100%;" src="javascript:void(0);"></iframe>'
			});
			
			document.body.appendChild(config.handler.list);
			document.body.appendChild(config.handler.shadow);
			
			return this;
		},
		// 显示选择框
		showSelectList : function() {
			_this.config.handler.list && (_this.config.handler.list.style.display = 'block',_this.config.handler.shadow.style.display = 'block');
			return this;
		},
		// 隐藏选择框
		hideSelectList : function() {
			_this.config.handler.list && (_this.config.handler.list.style.display = 'none',_this.config.handler.shadow.style.display = 'none');
			
			return this;
		},
		selectNodeForKeyboard : function(flag) {
			var config = _this.config,
				nodes  = config.handler.list.childNodes,
				len    = nodes.length;
			
			config.selectedIndex !== -1 && (nodes[config.selectedIndex].className = 'ly-advancedinputbox-node');
			
			if (config.selectedIndex == -1) {             // 未初始化
				config.selectedIndex = flag > 0 ? 0 : len - 1;
			} else if (config.selectedIndex == 0) {       // 已经移到最顶端
				config.selectedIndex = flag > 0 ? (len > 1 ? 1 : 0) : len - 1;
			} else if (config.selectedIndex == len - 1) { // 已经移到最底端
				config.selectedIndex = flag > 0 ? 0 : config.selectedIndex - 1;
			} else {
				config.selectedIndex += flag;
			}
			
			nodes[config.selectedIndex] && (nodes[config.selectedIndex].className = 'ly-advancedinputbox-node-selected');
			
			config.handler.list.scrollTop = nodes[config.selectedIndex].offsetTop + nodes[config.selectedIndex].offsetHeight - config.handler.list.offsetHeight;
			return this;
		},
		// 初始化接收器事件
		initAcceptor : function() {
			var acceptorHandler = function(obj, evt) {
				var config = _this.config,
					private = _this.private;
				
				!config.handler.list && private.createElement();
				
				!config.lock && private.queryData(this.value, evt);
			},
			keyboardHandler = function(obj, evt) {
				var nodes,
					config  = _this.config,
					keyCode = (evt || window.event).keyCode;
				
				config.lock = false;
				
				if (!_this.config.handler.list || config.handler.list.childNodes.length < 1) {
					return;
				}
				if (keyCode == 38 || keyCode == 40) {
					!config.handler.list && _this.private.createElement();
					_this.private.showSelectList();
					_this.private.selectNodeForKeyboard(keyCode == 38 ? -1 : 1);
				}
				if (keyCode == 13 && config.selectedIndex != -1) {
					nodes = config.handler.list.childNodes;
					config.selectedData = config.dataSources[nodes[config.selectedIndex].getAttribute('index')];
					
					config.acceptor.value = typeof config.selectedData === 'object' ? config.selectedData.text : config.selectedData;
					
					_this.private.hideSelectList();
				}
				
				keyCode == 27 && (config.lock = true, _this.private.hideSelectList());
			};
			Ly.addEvent('oninput', acceptorHandler, _this.config.acceptor);
			Ly.addEvent('onpropertychange', acceptorHandler, _this.config.acceptor);
			Ly.addEvent('onkeydown', keyboardHandler, _this.config.acceptor);
			Ly.addEvent('onclick',
				function(obj, evt) {
					evt = evt || window.event;
					(evt.target || evt.srcElement) === document.body && _this.private.hideSelectList();
				}, document);
			
			return this;
		}
	};
	
	if (!config.acceptor || config.acceptor.tagName.toLowerCase() !== 'input' || config.acceptor.type !== 'text') {
		alert('指定的acceptor参数无效！');
		return null;
	}
};

Ly.AdvancedInputBox.prototype = {
	version : '1.0a',
	/**
	 * 绑定数据源，两种格式：
	 * 1. data = ['abc', 'aaa', 'wd'];
	 * 2. data = [{
	 * 	 text : 'abc',
	 * 	 age : 23
	 * }, {
	 * 	 text : 'aaa',
	 * 	 age : 32
	 * }, {
	 * 	 text : 'wd',
	 * 	 age : 8
	 * }];
	 * 第一种格式时，返回的数据就是当前选中的数据
	 * 第二种格式时，text为显示并搜索的数据，若想获取数据则为：aib.age
	 */
	bind : function(data /* Array */) {
		data = data || {};
		
		if (data.constructor !== Array || data.length < 1) {
			alert('要绑定的数据必须是非空数组！');
			return false;
		}
		
		// 初始化返回结果的数据类型
		this.config.selectedData = typeof data[0] === 'object' ? {} : '';
		
		for (var i = 0, len = data.length; i < len; ++i) {
			if (data[i].constructor === Object && typeof data[i].text === 'undefined') {
				alert('数据格式不正确，未包含text属性！');
				return null;
			}
		}
		
		this.config.dataSources = data;
		
		return this;
	},
	// 渲染插件
	render : function() {
		this.private.initAcceptor();
		return this;
	},
	// 获取当前选择的数据对象
	getCurrentData : function() {
		return this.config.selectedData;
	}
};